import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.Scanner;
import java.util.zip.Inflater;

/**
 * 使用Frida捕获的密钥解密数美SDK加密数据
 * 
 * 使用步骤：
 * 1. 运行Frida Hook脚本，捕获32字节AES密钥
 * 2. 将密钥的hex字符串粘贴到此程序
 * 3. 自动解密data和tn
 */
public class DecryptWithCapturedKey {
    
    // 数美SDK返回的加密数据（从你的抓包或Hook中获取）
    private static final String DATA_BASE64 = "wHBy2LDIay6WCgEybO8bw/5OxmVd4N++OJpwr/Tgjw+TA8iZ4HAy4bN8UWtwmeGz+dqU/zX6myCireq+q465rqUqpXLhma2aEPqTaNvUTv/Y71kVpkMBkgrjMnVkIi/iBV5eKsrTPfLWO8bt0mSbLM8ghswC2m2YRInkqWXHrc8Nw0JsNjwCllOUdtwe3NuIx8oQuQ2fqj1G3g3xMp6B4sWBNAo+SjTNuKnS4chvbaD3RYnGvSLyNYu+sqbKeRNofCwVn0lVrjCAGtC9d5nqhFiGw0vWksPfmCRn7vRsl7LnqcXb+Fal/hhREBsaRJdMrst3vOEeQI6pt3RGKZ3VOsliNziKbLiNnXp2zY2fin32okAFwIOczPgeQA1yAM4FCnuT9FYAMn5ecAOY7WFhJPcOqVThy0giCJrBzpIzEHXTin+BWBO1PR8wMzBqpf6us9mhBZGzu40mzVN34xXK646aMr8f2DcD9yGO20v5icEz3OUcAeayMq+YKmBoypmvQUnaGa8pjr7RfvvajY+7pu6QHqRAQ3NLY1KjIoT3PKjabb7owQ1Txw5+Ajfjen7VEeF/Dq03nPMtNOpqD3tCdWDHWir+akJcEPtPzK4Bo2K3FrLBZt2igZD6/04jtwoAojHibKqUM1Rj5h2iijH65eAU1XKTpqDPNtcP5lwa1bFNV+GvuzHM+N4gcoxiELhQeG7xiUcsZrJvadkDO2z+If9vLkXTSdMKrqozUjLRapyXpULcVL8negHnj+2vKZVdoGiDhXlm23XDFjLY91ZqX2eGfGNmpJxftl83N6q4dyXpzD2gR/chHfm0CukVlL8P8aPAfEDcAsyQETc5oVLzetGVSkGBbQl+axZu8U2Ap9CXaTi1b2VcI3he19nvgG8XEFnwP6Tbicm5PDDsiRjo2MRqfuPLWkcSHTmBlS6w8yrzAvth9x/bBLg8XLs8M/B/dKSfOa9sbptfTMmEuuhWbnqCyqnFSUt8lsFlcUbJdK02TcMbd789pANnrKTTfFeOUehu5XReHng4DfV7f6boQmJPnZfwuR8qFwp7vwme235RTloktlkQu/2QFl2LmCv+/8Za43dEdFba9Ae6I1p+50zunyIjGTE6/9RT+g/zgagzgV/qDDSM5VF6E2Ic62W/KkpfSPMHAk5Jwg0LlsSMnFXYCynZoDZ5M8s62V15VaEII3s/6wPCu4lba/BxPanRtw60EVsvrJ7B0mnG+hcW8AGVeG1ZBIhgPH887/bY+05b0MnSkhjlrys8GKSaukVbtnrLJmjePt+LdLe6tH2NTwxjbHhJR028ZWaQKvdC5BD2hRflDMBPKL68D6YJ2bitqnKKdEqYHdCMXtOXh68XUqwfkoF3phQtYHyrqF4Wsgukf3/gAlt/yF0dXFTIUzoDTc34MEAaLFENVFDt4PUnYw2SRT8i/bhi3tcavu6Hnjs=";
    
    private static final String TN_BASE64 = "BMWDCPVx97y8KsnGiff6u4lmEogvgO30LtR/QvfGyqQWadycCGkbGhL7jCKvJTHmlK0k+fDR0XKq8U2IINpo0+aiWg8+nwaXQofOsilfXgDzG0DK9WJuwfcOrzGUHBn4yGVXDj+SUklPWbq0fojYGLYendkSnSLYTzeYIusMyZ3HD2djXyUvekKz0cp39JgrD/Ovj2Nrwn4ffPHcIXgSjpd02QXn4LNb4/7q465mfS2oQ5fRqiRMcnxpUhSD3Ty15bXVKJpPVqlqpM+tcUcXVV4g7ggOux361BsPius8as1vd7wuK44EOJ56MJeATqROjECur2bWdftoWydjfZj5sw==";
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("=" + "=".repeat(99));
        System.out.println("使用Frida捕获的密钥解密数美SDK数据");
        System.out.println("=" + "=".repeat(99));
        System.out.println();
        
        System.out.println("请按照以下步骤操作:");
        System.out.println("1. 运行Frida Hook脚本: run_frida.bat");
        System.out.println("2. 在应用中触发数美SDK调用");
        System.out.println("3. 从Frida输出中找到标记为 '⚠️⚠️⚠️ 与ep原始值匹配' 的密钥");
        System.out.println("4. 复制该密钥的hex字符串（64个字符）");
        System.out.println();
        
        System.out.print("请输入捕获到的32字节AES密钥 (hex格式, 64个字符): ");
        String keyHex = scanner.nextLine().trim();
        
        if (keyHex.isEmpty()) {
            System.out.println("\n使用示例密钥进行测试...");
            keyHex = "a1b2c3d4e5f67890123456789012345678901234567890123456789012345678";
            System.out.println("示例密钥: " + keyHex);
        }
        
        // 验证输入
        if (keyHex.length() != 64) {
            System.err.println("\n❌ 错误: 密钥长度不正确！");
            System.err.println("   期望: 64个hex字符 (32字节)");
            System.err.println("   实际: " + keyHex.length() + "个字符");
            System.err.println();
            System.err.println("示例正确格式:");
            System.err.println("a1b2c3d4e5f67890123456789012345678901234567890123456789012345678");
            return;
        }
        
        if (!keyHex.matches("[0-9a-fA-F]{64}")) {
            System.err.println("\n❌ 错误: 密钥格式不正确！只能包含0-9和a-f字符");
            return;
        }
        
        try {
            byte[] aesKey = hexToBytes(keyHex);
            
            System.out.println("\n" + "=".repeat(100));
            System.out.println("密钥信息");
            System.out.println("=".repeat(100));
            System.out.println("密钥长度: " + aesKey.length + " bytes");
            System.out.println("密钥 (hex): " + keyHex);
            System.out.println("密钥 (Base64): " + Base64.getEncoder().encodeToString(aesKey));
            
            // 解密data
            System.out.println("\n" + "=".repeat(100));
            System.out.println("解密 data");
            System.out.println("=".repeat(100));
            decryptAndDecompress("data", DATA_BASE64, aesKey);
            
            // 解密tn
            System.out.println("\n" + "=".repeat(100));
            System.out.println("解密 tn");
            System.out.println("=".repeat(100));
            decryptAndDecompress("tn", TN_BASE64, aesKey);
            
            System.out.println("\n" + "=".repeat(100));
            System.out.println("完成！");
            System.out.println("=".repeat(100));
            
        } catch (Exception e) {
            System.err.println("\n❌ 解密失败: " + e.getMessage());
            e.printStackTrace();
            
            System.out.println("\n" + "=".repeat(100));
            System.out.println("故障排查建议:");
            System.out.println("=".repeat(100));
            System.out.println("1. 确认密钥是否正确（从Frida输出中复制）");
            System.out.println("2. 确认密钥对应的是当前data/tn数据");
            System.out.println("3. 每次SDK调用可能使用不同的密钥，需要重新捕获");
            System.out.println("4. 如果看到 'bad padding' 错误，说明密钥不匹配");
        }
    }
    
    private static void decryptAndDecompress(String label, String base64Data, byte[] aesKey) {
        try {
            // 1. Base64解码
            byte[] dataWithIV = Base64.getDecoder().decode(base64Data);
            System.out.println("Base64解码后长度: " + dataWithIV.length + " bytes");
            
            // 2. 提取IV和密文
            byte[] iv = Arrays.copyOfRange(dataWithIV, 0, 16);
            byte[] encrypted = Arrays.copyOfRange(dataWithIV, 16, dataWithIV.length);
            
            System.out.println("IV (16 bytes): " + bytesToHex(iv));
            System.out.println("密文长度: " + encrypted.length + " bytes");
            
            // 3. AES-256-CBC解密
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            
            byte[] decrypted = cipher.doFinal(encrypted);
            System.out.println("✅ AES解密成功！解密后长度: " + decrypted.length + " bytes");
            
            // 4. zlib解压（raw deflate格式）
            Inflater inflater = new Inflater(true); // true = raw deflate
            inflater.setInput(decrypted);
            
            byte[] decompressed = new byte[1024 * 100]; // 100KB缓冲区
            int decompressedLen = inflater.inflate(decompressed);
            inflater.end();
            
            System.out.println("✅ zlib解压成功！解压后长度: " + decompressedLen + " bytes");
            
            // 5. 转换为UTF-8字符串
            String json = new String(decompressed, 0, decompressedLen, "UTF-8");
            
            System.out.println("\n🎉🎉🎉 成功解密 " + label + "！🎉🎉🎉");
            System.out.println("\n解密后的JSON:");
            System.out.println("-".repeat(100));
            
            // 美化输出JSON（简单格式化）
            String formatted = formatJson(json);
            System.out.println(formatted);
            System.out.println("-".repeat(100));
            
        } catch (javax.crypto.BadPaddingException e) {
            System.err.println("❌ AES解密失败: 密钥不正确或数据已损坏");
            System.err.println("   错误: " + e.getMessage());
            System.err.println("   提示: 请确认使用的是正确的AES密钥");
        } catch (java.util.zip.DataFormatException e) {
            System.err.println("❌ zlib解压失败: 数据格式不正确");
            System.err.println("   错误: " + e.getMessage());
            System.err.println("   AES解密可能成功了，但数据不是zlib压缩格式");
        } catch (Exception e) {
            System.err.println("❌ 处理失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    private static byte[] hexToBytes(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                                + Character.digit(hex.charAt(i+1), 16));
        }
        return data;
    }
    
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    private static String formatJson(String json) {
        // 简单的JSON美化（不依赖库）
        StringBuilder result = new StringBuilder();
        int indent = 0;
        boolean inString = false;
        
        for (int i = 0; i < json.length(); i++) {
            char c = json.charAt(i);
            
            if (c == '"' && (i == 0 || json.charAt(i-1) != '\\')) {
                inString = !inString;
            }
            
            if (!inString) {
                if (c == '{' || c == '[') {
                    result.append(c).append('\n');
                    indent++;
                    result.append("  ".repeat(indent));
                } else if (c == '}' || c == ']') {
                    result.append('\n');
                    indent--;
                    result.append("  ".repeat(indent));
                    result.append(c);
                } else if (c == ',') {
                    result.append(c).append('\n');
                    result.append("  ".repeat(indent));
                } else if (c == ':') {
                    result.append(c).append(' ');
                } else if (!Character.isWhitespace(c)) {
                    result.append(c);
                }
            } else {
                result.append(c);
            }
        }
        
        return result.toString();
    }
}


